﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Ymatou.CommonService;
using ServiceStack.Text;
using System.Threading.Tasks.Dataflow;
namespace YmtAuth.LogService
{
    class LogService
    {
        private Dictionary<string, Func<IEnumerable<LogEntityBase>, string, Task>> _action = new Dictionary<string, Func<IEnumerable<LogEntityBase>, string, Task>>();
        public void RegisterAction(string logType, Func<IEnumerable<LogEntityBase>, string, Task> action)
        {
            _action[logType] = action;
        }
        public int GetInsertBatch
        {
            get
            {
                var batchsize = ConfigurationManager.AppSettings["WriteSQLBatchSize"];
                if (string.IsNullOrEmpty(batchsize)) return 500;
                return Convert.ToInt32(batchsize);
            }
        }
        public void Store(IEnumerable<LogEntityBase> logs)
        {
            //按日志类型分组
            var groupLogs = logs.GroupBy(e => e.LogType);
            foreach (var logEntity in groupLogs)
            {
                _action[logEntity.Key](logEntity.Select(e => e), logEntity.Key)
                    .ContinueWith(t => ApplicationLog.Error(logEntity.Key + " error ", t.Exception), TaskContinuationOptions.OnlyOnFaulted);
                #region [老的分支逻辑]
                ////注册日志
                //if (logEntity.Key == "YmatouUserRegisterLoginLog")
                //{
                //    _WriteUserRegisterLogToSQL(logEntity.Select(e => e as UserRegisterHistory), logEntity.Key).ContinueWith(t => ApplicationLog.Error("_WriteUserRegisterLogToSQL error", t.Exception), TaskContinuationOptions.OnlyOnFaulted);
                //}
                ////黑名单日志
                //else if (logEntity.Key == "BlackListIpRequestLog")
                //{
                //    _WriteBlackListIpRequestLogToSQL(logEntity.Select(e => e as BlackListIpRequestLog), logEntity.Key).ContinueWith(t => ApplicationLog.Error("_WriteBlackListIpRequestLog error", t.Exception), TaskContinuationOptions.OnlyOnFaulted);
                //}
                ////token认证日志
                //else if (logEntity.Key == "YmatouUserTokenAuthLog"
                //    || logEntity.Key == "AuthSafeVerifyLog"
                //    || logEntity.Key == "YmatouThirdPartyUserLoginLog")
                //{
                //    _WriteLoginLogToSQL(logEntity.Select(e => e as AuthSafeVerifyLog), logEntity.Key).ContinueWith(t => ApplicationLog.Error("_WriteLogToSQL error", t.Exception), TaskContinuationOptions.OnlyOnFaulted);
                //}
                #endregion
            }
        }
        public async Task _WriteLoginLogToSQL(IEnumerable<LogEntityBase> loginlog, string LogKey)
        {
            var sqlLogStore = ConfigurationManager.AppSettings["EnableSqlLogStore"];
            if (string.IsNullOrEmpty(sqlLogStore) || sqlLogStore == "1")
            {

                var action = new ActionBlock<IEnumerable<UserLoginLogHistory>>(async c =>
                    await SqlHelp.InsertLoginLog(c, WriteSQLTimeOut, LogKey, ConfigurationManager.AppSettings[LogKey]));
                var batch = new BatchBlock<UserLoginLogHistory>(loginlog.Count());
                foreach (var log in loginlog)
                    await batch.SendAsync(log as UserLoginLogHistory).ConfigureAwait(false);
                batch.LinkTo(action);
                await batch.Completion.ContinueWith(t => action.Complete());
                batch.Complete();
                action.Completion.Wait();
            }
        }

        public async Task _WriteSafeVerifyLogToSQL(IEnumerable<LogEntityBase> safeVerifyLog, string LogKey)
        {
            var sqlLogStore = ConfigurationManager.AppSettings["EnableSqlLogStore"];
            if (string.IsNullOrEmpty(sqlLogStore) || sqlLogStore == "1")
            {

                var action = new ActionBlock<IEnumerable<SafeVerifyLog>>(async c =>
                    await SqlHelp.InsertSafeVerifyLog(c, WriteSQLTimeOut, LogKey, ConfigurationManager.AppSettings[LogKey]));
                var batch = new BatchBlock<SafeVerifyLog>(safeVerifyLog.Count());
                foreach (var log in safeVerifyLog)
                    await batch.SendAsync(log as SafeVerifyLog).ConfigureAwait(false);
                batch.LinkTo(action);
                await batch.Completion.ContinueWith(t => action.Complete());
                batch.Complete();
                action.Completion.Wait();
            }
        }

        public async Task _UpdateUserIpAreaAuthTime(IEnumerable<LogEntityBase> loginlog, string LogKey)
        {
            var action = new ActionBlock<IEnumerable<UpdateUserIpAreaTimeLog>>(async c =>
               await SqlHelp.UpdateUserIpAreaAuthTimeLog(c, WriteSQLTimeOut, LogKey));
            var batch = new BatchBlock<UpdateUserIpAreaTimeLog>(loginlog.Count());
            foreach (var log in loginlog)
                await batch.SendAsync(log as UpdateUserIpAreaTimeLog).ConfigureAwait(false);
            batch.LinkTo(action);
            await batch.Completion.ContinueWith(t => action.Complete());
            batch.Complete();
            action.Completion.Wait();
        }

        public async Task _WriteTokenAuthLogToSQL(IEnumerable<LogEntityBase> loginlog, string LogKey)
        {
            var action = new ActionBlock<IEnumerable<TokenAuthLog>>(async c =>
                await SqlHelp.InsertTokenAuthLog(c, WriteSQLTimeOut, LogKey));
            var batch = new BatchBlock<TokenAuthLog>(loginlog.Count());
            foreach (var log in loginlog)
                await batch.SendAsync(log as TokenAuthLog).ConfigureAwait(false);
            batch.LinkTo(action);
            await batch.Completion.ContinueWith(t => action.Complete());
            batch.Complete();
            action.Completion.Wait();
        }
        public async Task _WriteThirdPartyLogToSQL(IEnumerable<LogEntityBase> loginlog, string LogKey)
        {
            var action = new ActionBlock<IEnumerable<ThirdPartyUserLoginLog>>(async c =>
                await SqlHelp.InsertThirdPartyLoginLog(c, WriteSQLTimeOut, LogKey));
            var batch = new BatchBlock<ThirdPartyUserLoginLog>(loginlog.Count());
            foreach (var log in loginlog)
                await batch.SendAsync(log as ThirdPartyUserLoginLog).ConfigureAwait(false);
            batch.LinkTo(action);
            await batch.Completion.ContinueWith(t => action.Complete());
            batch.Complete();
            action.Completion.Wait();
        }
        public async Task _WriteUserRegisterLogToSQL(IEnumerable<LogEntityBase> registerlog, string logKey)
        {
            var action = new ActionBlock<IEnumerable<UserRegisterHistory>>(async c =>
                await SqlHelp.InsertUserRegisterLog(c, WriteSQLTimeOut, logKey));
            var batch = new BatchBlock<UserRegisterHistory>(registerlog.Count());
            foreach (var log in registerlog)
                await batch.SendAsync(log as UserRegisterHistory).ConfigureAwait(false);
            batch.LinkTo(action);
            await batch.Completion.ContinueWith(t => action.Complete());
            batch.Complete();
            action.Completion.Wait();
        }
        public async Task _WriteBlackListIpRequestLogToSQL(IEnumerable<LogEntityBase> blacklistIpLog, string logKey)
        {
            var action = new ActionBlock<IEnumerable<UserLockLog>>(async c =>
                await SqlHelp.UserLockedLog(c, WriteSQLTimeOut, logKey));
            var batch = new BatchBlock<UserLockLog>(blacklistIpLog.Count());
            foreach (var log in blacklistIpLog)
                await batch.SendAsync(log as UserLockLog).ConfigureAwait(false);
            batch.LinkTo(action);
            await batch.Completion.ContinueWith(t => action.Complete());
            batch.Complete();
            action.Completion.Wait();
        }
        public void DumpQueueLogToDisk(IEnumerable<LogEntityBase> logs)
        {
            try
            {
                Task.Factory.StartNew(() => ApplicationLog.Info(logs.Dump()));
                ApplicationLog.Info("[DumpQueueLogToDisk] done.");
            }
            catch (Exception)
            {
                //ignore
            }
          
        }
        public TimeSpan WriteSQLTimeOut
        {
            get
            {
                var timeout = ConfigurationManager.AppSettings["WriteSQLTimeOut"];
                if (string.IsNullOrEmpty(timeout)) return TimeSpan.FromSeconds(3);
                TimeSpan t;
                if (TimeSpan.TryParse(timeout, out t)) return t;
                else return TimeSpan.FromSeconds(3);
            }
        }
    }
}
